#include "Creature.h"
#include "MonsterInfo.h"
#include "magicitem.h"
#include "world.h"
#include "Item.h"
#include "tile.h"
#include "gui.h"

extern volatile int frametick;

uint    Monster::s_id = 0;

Monster *Monster::New(ushort type)
{
    if (type < INST(MonsterInfo).size())
        return new Monster(type);
    return NULL;
}

Monster::Monster(ushort type) : Creature(), m_id(++s_id), m_mtype(type), m_frame(0), m_oldframe(0)
{
    if (type >= INST(MonsterInfo).size())
        throw MonsterIndexOutRange();

    Live &live = getLive();
    live = Live(INST(MonsterInfo)[type].m_hp, 0);
}

void Monster::Action()
{
        if (dead())
                return;

        m_frame = frametick;
        if (m_frame - m_oldframe > INST(MonsterInfo)[m_mtype].m_frame)
        {
        }
}

const char *Monster::name() const
{
        return INST(MonsterInfo)[m_mtype].m_name.c_str();
}

void Monster::draw(BITMAP *surface)
{
        assert(m_mtype < INST(MonsterInfo).size());

        const MonsterAttr &attr = INST(MonsterInfo)[m_mtype];
        const Rect &rect = getRect();

        short sx, sy;
        mapxy_to_screenxy(rect.x, rect.y, sx, sy);
        if (!dead() || !attr.m_dtile)
                draw_sprite(surface, attr.m_tile, sx, sy);
        else
                draw_sprite(surface, attr.m_dtile, sx, sy);

//        INST(SeenObj).add(this, Rect(sx, sy, attr.m_tile->w, attr.m_tile->h));
}

Player::Player ()
{
        memset(m_items, 0, sizeof(m_items));
        memset(m_body, 0, sizeof(m_body));

        m_spirte = new GifAnimation("Tile/d2-green_dragon_ani.gif");
        m_spirte->setloops(0x0fffffff);
}

void Player::draw(BITMAP *surface)
{
        if (INST(Config).direction == DIR_RIGHT)
                draw_sprite_h_flip(surface, m_spirte->getCurFrame(), INST(Config).player_x, INST(Config).player_y);
        else
                draw_sprite(surface, m_spirte->getCurFrame(), INST(Config).player_x, INST(Config).player_y);
        m_spirte->NextFrame();
}

void Player::attack(ushort mid, ushort moffset)
{
}

Item *Player::getInven(short row, short col)
{
        return m_items[row * INV_COL + col];
}

Item *Player::getBody(short pos)
{
        assert(pos < BODY_MAX);
        return m_body[pos];
}

bool Player::use(Item *item)
{
        if (item->canEquip()) {
                return equip(item);
        } else {
                Item::Type useResult = item->use(this);
                if (useResult == Item::USE_FAILED) {
                        return false;
                } else if (useResult == Item::USE_REMOVE) {
                        destroyItem(item);
                } else if (useResult == Item::USE_REMAIN) {
                        return true;
                }

                return true;
        }
}

bool Player::addItem(Item *item)
{
        for (unsigned i = 0; i < INV_ROW*INV_COL; ++i) {
                if (m_items[i] == NULL) {
                        m_items[i] = item;
                        item->toBody(false);
                        return true;
                }
        }

        return false;
}

bool Player::_dropItem(Item *item)
{
        for (unsigned i = 0; i < INV_ROW*INV_COL; ++i) {
                if (m_items[i] == item) {
                        m_items[i] = NULL;
                        return true;
                }
        }

        return false;
}

bool Player::throwItem(Item *item)
{
        if (_dropItem(item))
        {
                MapVisitor mv;
                if (!mv.put_item(item, test::g_map, INST(Config).cur_x+8, INST(Config).cur_y+8))
                {
                        delete item;
                }
                return true;
        }

        return false;
}

bool Player::destroyItem(Item *item)
{
        if (_dropItem(item)) {
                delete item;
                return true;
        }

        return false;
}

bool Player::equip(Item *item)
{
        int pos = item->getEquipPos();
        if (pos >= BODY_MAX)
                return false;

        for (unsigned i = 0; i < INV_ROW*INV_COL; ++i) {
                if (m_items[i] == item) {
                        m_items[i] = NULL;
                        if (m_body[pos] && !unequip(m_body[pos])) {
                                m_items[i] = item;
                                return false;
                        }
                        m_body[pos] = item;
                        item->toBody(true);
                        return true;
                }
        }

        return false;
}

bool Player::unequip(Item *item)
{
        int pos = item->getEquipPos();
        assert(pos < BODY_MAX && m_body[pos] == item);

        for (unsigned i = 0; i < INV_ROW*INV_COL; ++i) {
                if (m_items[i] == NULL) {
                        m_items[i] = m_body[pos];
                        m_items[i]->toBody(false);
                        m_body[pos] = NULL;
                        return true;
                }
        }

        return false;
}
/*
MonsterRecord *SeenObj::SeenMonster(short x, short y)
{
        vector<MonsterRecord>::iterator it, endit = m_seens.end();
        for (it = m_seens.begin(); it != endit; ++it) {
                if (it->m_postion.inRect(x, y))
                        return &(*it);
        }
        return NULL;
}

ItemRecord *SeenObj::SeenItem(short x, short y)
{
        vector<ItemRecord>::iterator it, endit = m_items.end();
        for (it = m_items.begin(); it != endit; ++it) {
                if (it->m_postion.inRect(x, y))
                        return &(*it);
        }
        return NULL;
}

void SeenObj::add(Item *item, const Rect &pos, short x, short y)
{
        ItemRecord record;
        record.m_item = item;
        record.m_postion = pos;
        record.m_mapx = x;
        record.m_mapy = y;
        m_items.push_back(record);
}

void SeenObj::add(Monster *monster, const Rect &pos)
{
        MonsterRecord record;
        record.m_monster = monster;
        monster->used();
        record.m_postion = pos;
        m_seens.push_back(record);
}

void SeenObj::clear()
{
        m_seens.clear();
        m_items.clear();
}

void SeenObj::Action()
{
        vector<MonsterRecord>::iterator it, endit = m_seens.end();
        for (it = m_seens.begin(); it != endit; ++it) {
                Monster *monster = Monster::GetByOffset(it->m_offset);
                if (monster && monster->getId() == it->m_id) {
                        monster->Action();
                }
        }
}

void SeenObj::remove(ItemRecord &m)
{
        vector<ItemRecord>::iterator it, endit = m_items.end();
        for (it = m_items.begin(); it != endit; ++it) {
                if (it->m_item == m.m_item) {
                        m_items.erase(it);
                        return;
                }
        }
}
*/
Npc::Npc()
{
        addSellItem(new Item(Item::ITEM_ARMET, INST(TileManager).getTile(0)));
        addSellItem(new Item(Item::ITEM_ARMET, INST(TileManager).getTile(1)));
        addSellItem(new Item(Item::ITEM_ROBE,  INST(TileManager).getTile(18)));
        addSellItem(new Item(Item::ITEM_ROBE,  INST(TileManager).getTile(19)));
        addSellItem(new Item(Item::ITEM_WEAPON, INST(TileManager).getTile(20)));
        addSellItem(new Item(Item::ITEM_WEAPON, INST(TileManager).getTile(21)));
        addSellItem(new Item(Item::ITEM_WEAPON, INST(TileManager).getTile(22)));
        addSellItem(new Item(Item::ITEM_WEAPON, INST(TileManager).getTile(23)));
        addSellItem(new Item(Item::ITEM_WEAPON, INST(TileManager).getTile(24)));
        addSellItem(new Item(Item::ITEM_WEAPON, INST(TileManager).getTile(25)));
        addSellItem(new Item(Item::ITEM_WEAPON, INST(TileManager).getTile(26)));
        addSellItem(new Item(Item::ITEM_WEAPON, INST(TileManager).getTile(27)));
        addSellItem(new Item(Item::ITEM_WEAPON, INST(TileManager).getTile(28)));
        addSellItem(new Item(Item::ITEM_WEAPON, INST(TileManager).getTile(29)));
        addSellItem(new Item(Item::ITEM_HP_POSITION, INST(TileManager).getTile(30)));
        addSellItem(new Item(Item::ITEM_HP_POSITION, INST(TileManager).getTile(31)));
        addSellItem(new Item(Item::ITEM_HP_POSITION, INST(TileManager).getTile(32)));
        addSellItem(new Item(Item::ITEM_HP_POSITION, INST(TileManager).getTile(33)));
        addSellItem(new Item(Item::ITEM_HP_POSITION, INST(TileManager).getTile(34)));
        bindToSellGui();
}

Npc::~Npc()
{
        std::for_each(m_sells.begin(), m_sells.end(), Deleter<Item>());
}

void Npc::addSellItem(Item *item)
{
        m_sells.push_back(item);
}

void Npc::bindToSellGui()
{
        GuiEvent arg;
        arg.m_type = ET_BIND_SELL;
        arg.m_data = (void *)&m_sells;
        INST(GuiManager).GuiObjCommand(GSELLLIST , arg);
}

